package com.autoscript.ext.xmldata.sql.parse;

import com.autoscript.ext.sqlparse.SqlParseConstant;
import com.autoscript.ext.sqlparse.entity.Column;
import com.autoscript.ext.sqlparse.entity.ForeignItem;
import com.autoscript.ext.sqlparse.entity.TableItem;
import com.autoscript.ext.sqlparse.service.MysqlSqlParse;
import com.autoscript.ext.sqlparse.service.SqlParseFactory;
import com.autoscript.ext.xmldata.dbmodel.*;
import com.autoscript.ui.helper.StringHelper;
import com.autoscript.ui.helper.TypeConversionHelper;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * sql 语句解析器
 */

public class SqlParse implements  ISqlParse{
    private static final Logger log = Logger.getLogger(String.valueOf(SqlParse.class));
    @Override
    public IDBModel parseCreateSql(String sqlContent, String dbType) throws Exception {
        if(SqlParseConstant.MYSQL.equals(dbType)){
            MysqlSqlParse mysqlParse = SqlParseFactory.getInstance().getService(SqlParseConstant.MYSQL);
            List<TableItem> tableItems = mysqlParse.parseCreateSql(sqlContent, dbType);
            IDBModel sqlModel = new DBModel();
            //循环转换TableItem
            // 循环解析每个table 模型
            ArrayList<ITableModel> tableModels;
            tableModels = new ArrayList<ITableModel>();
            for (TableItem tableItem : tableItems) {
                tableModels.add(toTableModel(tableItem));
            }
            sqlModel.setTableModels(tableModels);
            //解析外键
            sqlModel.setReferenceModels(parseReference(tableItems));
            return sqlModel;
        }else
            throw new Exception("不支持数据库类型!");
    }

    /**
     * 将sql
     * @param tableItem
     * @return
     */
    private ITableModel toTableModel(TableItem tableItem) {
        ITableModel tableModel = new TableModel();
        //设置表id
        //tableModel.setId(table.getAttributeVal(ID));
        //表中文名,如果没有注释，则用英文名
        if(StringHelper.isEmpty(tableItem.getComment())||NULL.equalsIgnoreCase(tableItem.getComment())){
            tableModel.setName(tableItem.getTable());
        }else {
            tableModel.setName(tableItem.getComment());
        }

        tableModel.setCode(tableItem.getTable());
        tableModel.setComment(NULL.equalsIgnoreCase(tableItem.getComment())?"":tableItem.getComment());

        // 解析列
        parseColumns(tableItem, tableModel);
        // 解析主键
        parseKeys(tableItem, tableModel);
        return tableModel;
    }

    /**
     * 解析外键
     * @param tableItems
     * @return
     */
    private List<IReferenceModel> parseReference(List<TableItem> tableItems) {
        List<IReferenceModel> referenceModels = new ArrayList<>();
        for(TableItem tableItem:tableItems) {
            if(tableItem.getForeignItems()!=null) {
                for (ForeignItem foreignItem : tableItem.getForeignItems()) {
                    IReferenceModel referenceModel = new ReferenceModel();
                    referenceModel.setChildTable(tableItem.getTable());
                    referenceModel.setParentTable(foreignItem.getParentTableName());
                    referenceModel.setCode(foreignItem.getName());
                    List<IReferenceJoinModel> referenceJoinModels = new ArrayList<>();
                    for (int i = 0; i < foreignItem.getParentFieldNameList().size(); i++) {
                        IReferenceJoinModel referenceJoinModel = new ReferenceJoinModel();
                        referenceJoinModel.setParentColumnName(foreignItem.getParentFieldNameList().get(i));
                        referenceJoinModel.setChildColumnName(foreignItem.getChildFieldNameList().get(i));
                        referenceJoinModels.add(referenceJoinModel);
                    }
                    referenceModel.setReferenceJoinModels(referenceJoinModels);
                    referenceModels.add(referenceModel);
                }
            }
        }
        return referenceModels;
    }

    /**
     * 解析主键
     * @param tableItem
     * @param tableModel
     */
    private void parseKeys(TableItem tableItem, ITableModel tableModel) {
        IKeyModel keyModel;

        keyModel = new KeyModel();
        List<String> keyColumnNames = new ArrayList<>();
        keyColumnNames.addAll(tableItem.getPkColumns());
        keyModel.setColumns(keyColumnNames);
        tableModel.setKey(keyModel);
    }

    /**
     * 解析列
     * @param tableItem
     * @param tableModel
     */
    private void parseColumns(TableItem tableItem, ITableModel tableModel) {
        // 循环解析列模型
        List<IColumnModel> columnModels = new ArrayList<IColumnModel>();
        //循环构造列模型
        for(Column column:tableItem.getColumn()){
            IColumnModel columnModel = new ColumnModel();
            //如果列没有注释，则用列名
            if(StringHelper.isEmpty(column.getFieldName())){
                columnModel.setName(column.getFieldName());
            }else{
                columnModel.setName(column.getComment());
            }
            //字段名
            columnModel.setCode(column.getFieldName());
            //数据类型
            //如果有括号，截断括号
            int pos = column.getDataType().indexOf(LEFT_BRACKET);
            if(pos>=0){
                columnModel.setDataType(column.getDataType().substring(0,pos));
                //顺便获取长度及小数位
                int dotPos = column.getDataType().indexOf(COMMA);
                if(dotPos>=0){
                    try {
                        columnModel.setLength(TypeConversionHelper.StringToInt(column.getDataType().substring(pos + 1, dotPos)));
                    }catch (Exception e){
                        log.throwing(this.getClass().getName(),"parseColumns",e);
                        columnModel.setLength(0);
                    }
                    int rightBracketPos = column.getDataType().indexOf(RIGHT_BRACKET);
                    if(rightBracketPos>=0) {
                        try {
                            columnModel.setPrecision(TypeConversionHelper.StringToInt(column.getDataType().substring(dotPos + 1, rightBracketPos).trim()));
                        }catch (Exception e){
                            log.throwing(this.getClass().getName(),"parseColumns",e);
                            columnModel.setPrecision(0);
                        }
                    }else{
                        try {
                            columnModel.setPrecision(TypeConversionHelper.StringToInt(column.getDataType().substring(dotPos + 1).trim()));
                        }catch (Exception e){
                            log.throwing(this.getClass().getName(),"parseColumns",e);
                            columnModel.setPrecision(0);
                        }
                    }
                }else{
                    int rightBracketPos = column.getDataType().indexOf(RIGHT_BRACKET);
                    if(rightBracketPos>=0) {
                        try {
                            columnModel.setLength(TypeConversionHelper.StringToInt(column.getDataType().substring(pos + 1, rightBracketPos)));
                        }catch (Exception e){
                            log.throwing(this.getClass().getName(),"parseColumns",e);
                            columnModel.setLength(0);
                        }
                    }else{
                        try {
                            columnModel.setLength(TypeConversionHelper.StringToInt(column.getDataType().substring(pos + 1)));
                        }catch (Exception e){
                            log.throwing(this.getClass().getName(),"parseColumns",e);
                            columnModel.setLength(0);
                        }
                    }
                }
            }else{
                columnModel.setDataType(column.getDataType());
                columnModel.setLength(0);
                columnModel.setPrecision(0);
            }
            //是否允许为空
            if(column.isAllownull()){
                columnModel.setMandatory(false);
            }else{
                columnModel.setMandatory(true);
            }
            // 加入列列表
            columnModels.add(columnModel);

        }
        // 设置到表模型
        tableModel.setColumnModels(columnModels);
    }
}
